| |
This program
generates a stand-alone class that prints "hello world" a
few times when invoked. As usual, start with the class hierarchy and
the initialization code.
// class hierarchy
ClassEnv nclass = new ClassEnv();
nclass.setClass(new ClassCP("out"));
nclass.setSuperClass(new ClassCP("java/lang/Object"));
nclass.setClassAccess((short)ACC_PUBLIC);
// Initialization code
CodeAttr init = new CodeAttr();
init.addInsn(new Insn(opc_aload_0));
init.addInsn(new Insn
(opc_invokenonvirtual,
new MethodCP
("java/lang/Object", "<init>", "()V")));
init.addInsn(new Insn(opc_return));
|
Now we create a new code object which actually does the hello world
bit.
// Actual code to print string
CodeAttr doit = new CodeAttr();
// store refs in local variables
doit.addInsn(new Insn
(opc_getstatic,
new FieldCP("java/lang/System",
"out",
"Ljava/io/PrintStream;")));
doit.addInsn(new Insn(opc_astore_1));
doit.addInsn(new Insn(opc_ldc,
new StringCP("Hello World")));
doit.addInsn(new Insn(opc_astore_2));
// Loop index in var reg 3
doit.addInsn(new Insn(opc_bipush, 5));
doit.addInsn(new Insn(opc_istore_3));
// Start the loop
Label loop = new Label("loop");
doit.addInsn(loop);
doit.addInsn(new Insn(opc_aload_1));
doit.addInsn(new Insn(opc_aload_2));
doit.addInsn(new Insn
(opc_invokevirtual,
new MethodCP("java/io/PrintStream",
"println",
"(Ljava/lang/String;)V")));
doit.addInsn(new IincInsn(3, -1));
doit.addInsn(new Insn(opc_iload_3));
doit.addInsn(new Insn(opc_ifne, loop));
doit.addInsn(new Insn(opc_return));
// set the right
// sizes for code
doit.setStackSize((short)3); doit.setVarSize((short)4);
|
This piece of code shows how labels are defined from the package.
The Label class
allows you to insert labels into the body of a code. Labels are
uniquely identified by the name they are given, although you can
choose to reuse Labels if you like.
The rest of the code is just general instructions to keep track
of the loop index and call System.out.println at the right places.
You will notice that the
setStackSize is used to explicitly set the stack height in
the class. The ClassEnv does not do this for you, so
always remember to set the correct stack and local variable sizes
in the class.
The two methods are now added into the class file
nclass.addMethod
((short)ACC_PUBLIC, "<init>",
"()V", init, null);
// Add the printing code
nclass.addMethod
((short)(ACC_PUBLIC|ACC_STATIC), "main",
"([Ljava/lang/String;)V", doit, null);
// write it all out
nclass.write(new DataOutputStream
(new FileOutputStream("out.class")));
|
Now continuing on by compiling, generating, verifying and running the program
% javac -g -d . examples/hworld.java
% java hworld
% ls -l out.class
-rw-r--r-- 1 kbs 341 Dec 31 11:56 out.class
% javap -verify out
Class out succeeds
% java out
Hello World
Hello World
Hello World
Hello World
Hello World
%
|
|